package com.wiscamp.ninechapters.panels.application.services;

import com.wiscamp.ninechapters.panels.application.assemblers.MenuAssembler;
import com.wiscamp.ninechapters.panels.application.assemblers.PermissionAssembler;
import com.wiscamp.ninechapters.panels.application.assemblers.RoleAssembler;
import com.wiscamp.ninechapters.panels.application.command.BindUnbindRoleMenuCommand;
import com.wiscamp.ninechapters.panels.application.command.BindUnbindRolePermissionCommand;
import com.wiscamp.ninechapters.panels.application.command.CreateRoleCommand;
import com.wiscamp.ninechapters.panels.application.command.UpdateRoleCommand;
import com.wiscamp.ninechapters.panels.application.vo.MenuVO;
import com.wiscamp.ninechapters.panels.application.vo.PermissionVO;
import com.wiscamp.ninechapters.panels.application.vo.RoleVO;
import com.wiscamp.ninechapters.panels.domain.repositories.RoleRepository;
import com.wiscamp.ninechapters.panels.domain.services.RoleService;
import cube.common.core.CollectionUtils;
import cube.ddd.application.BaseAppService;
import cube.ddd.application.command.DeleteCommand;
import cube.ddd.application.command.DisableCommand;
import cube.ddd.application.command.EnableCommand;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.common.query.PagedObjects;
import cube.ddd.common.query.PagedQuery;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.Valid;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class RoleAppService extends BaseAppService {

    private final RoleRepository roleRepository;

    private final RoleService roleService;

    public RoleAppService(RoleRepository roleRepository, RoleService roleService) {
        this.roleRepository = roleRepository;
        this.roleService = roleService;
    }

    @HandleServiceException
    public RoleVO getRole(long roleId) {
        return AppServiceUtils.getById(roleId, roleService::getRole,
                RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public RoleVO getRoleByCode(long appId, String roleCode) {
        return AppServiceUtils.getByIdAndText(appId, roleCode, roleRepository::getRoleByCode,
                RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public Collection<RoleVO> getRolesByName(long appId, String roleName) {
        return AppServiceUtils.getListByIdAndText(appId, roleName, roleRepository::getRolesByName,
                RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public Collection<RoleVO> getRolesByIds(Collection<Long> roleIds) {
        var roles = roleRepository.getRolesByIds(roleIds);
        return CollectionUtils.toArrayList(roles, RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public Collection<RoleVO> getAvailableRoles(long appId) {
        var roles = roleRepository.getAvailableRoles(appId);
        return CollectionUtils.toArrayList(roles, RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public PagedObjects<RoleVO> getRolesByQuery(PagedQuery pagedQuery) {
        var pagedObjects = roleRepository.getRolesByQuery(pagedQuery);
        return AppServiceUtils.convertPagedObjects(pagedObjects, RoleAssembler.Instance::toRoleVO);
    }

    @HandleServiceException
    public Collection<MenuVO> getMenusByRole(long roleId) {
        return AppServiceUtils.getListById(roleId, roleService::getMenusByRole,
                MenuAssembler.Instance::toMenuVO);
    }

    @HandleServiceException
    public Collection<PermissionVO> getPermissionsByRole(long roleId) {
        return AppServiceUtils.getListById(roleId, roleService::getPermissionsByRole,
                PermissionAssembler.Instance::toPermissionVO);
    }

    @HandleServiceException
    public RoleVO createRole(@Valid CreateRoleCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), roleService::createRole,
                RoleAssembler.Instance::toRoleVO, RoleAssembler.Instance::fromCreateCommand);
    }

    @HandleServiceException
    public RoleVO updateRole(@Valid UpdateRoleCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), roleService::updateRole,
                RoleAssembler.Instance::toRoleVO, RoleAssembler.Instance::fromUpdateCommand);
    }

    @HandleServiceException
    public boolean deleteRole(@Valid DeleteCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), roleService::deleteRole);
    }

    @HandleServiceException
    public boolean enableRole(@Valid EnableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.enable(command.getId(), command.getOperatorId(), roleService::enableRole);
    }

    @HandleServiceException
    public boolean disableRole(@Valid DisableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.disable(command.getId(), command.getOperatorId(), roleService::disableRole);
    }


    @HandleServiceException
    public boolean bindRoleMenu(@Valid BindUnbindRoleMenuCommand command) {
        command.setOperatorId(getCurrentUserId());
        return roleService.bindRoleMenu(command.getRoleId(), command.getMenuId());
    }

    @HandleServiceException
    public boolean unbindRoleMenu(@Valid BindUnbindRoleMenuCommand command) {
        command.setOperatorId(getCurrentUserId());
        return roleService.unbindRoleMenu(command.getRoleId(), command.getMenuId());
    }

    @HandleServiceException
    public boolean bindRolePermission(@Valid BindUnbindRolePermissionCommand command) {
        command.setOperatorId(getCurrentUserId());
        return roleService.bindRolePermission(command.getRoleId(), command.getPermissionId());
    }

    @HandleServiceException
    public boolean unbindRolePermission(@Valid BindUnbindRolePermissionCommand command) {
        command.setOperatorId(getCurrentUserId());
        return roleService.unbindRolePermission(command.getRoleId(), command.getPermissionId());
    }
}
